package com.qf.realm;

import com.qf.pojo.SysUsers;
import com.qf.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;

/**
 * 自定义Realm类
 * 1. 获取数据库中的用户名密码 : 根据用户名, 到mysql数据库的用户表中查询数据库中的用户名密码, 交给SecurityManager核心对象
 * 2. 授权 : 如果用户名密码正确, 赋予用户对应的角色和权限
 * @author 千锋健哥
 */
public class MyUserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 授权方法: 用户名密码校验成功后自动执行这个方法进行用户授权, 赋予用户对应的角色和权限
     * @param principalCollection shiro框架中在session会话里面存储的当前登录用户的对象
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("=========自定义Realm,==doGetAuthorizationInfo方法, 授权: 根据用户名获取用户的角色权限数据赋予这个用户==============");

        //1. 获取认证的时候shiro框架中session存储的用户对象
        SysUsers user = (SysUsers)principalCollection.getPrimaryPrincipal();
        int userId = user.getId();

        //2. 根据用户id, 到数据库角色表中获取用户的角色信息
        Set<String> roleList = userService.findRolesByUid(userId);

        //3. 根据用户id, 到数据库权限表或者菜单表中获取用户的权限信息
        Set<String> permList = userService.findPermByUid(userId);

        //4. 封装shiro规定的角色权限对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        //5. 将角色数据赋予shiro的权限对象
        authorizationInfo.setRoles(roleList);

        //6. 将权限数据赋予shiro的权限对象
        authorizationInfo.setStringPermissions(permList);

        //7. 返回shiro的权限对象给, securityManager核心对象
        return authorizationInfo;
    }

    /**
     * 认证方法: 从mysql中, 根据用户名, 获取user表中的用户对象, 交给shiro框架的SecurityManager核心管理
     * @param token 消费者在页面输入的用户名, 密码对象
     * @return
     * @throws
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("================自定义Realm, doGetAuthenticationInfo方法, 登录认证, 判断用户名密码是否正确==========================");
        //1. 获取用户在登录页面中输入的用户名
        String userName = (String)token.getPrincipal();

        //2. 获取用户在登录页面中输入的密码, shiro规定密码必须转换成char类型数组, 再转换成string字符串
        String password = new String((char[])token.getCredentials());

        //3. 根据用户名到数据库用户表中获取用户对象
        SysUsers user = userService.findUserByName(userName);

        //4. 如果用户对象获取不到, 抛异常, 用户不存在
        if (user == null) {
            throw new UnknownAccountException("用户不存在!");
        }

        //5. 如果用户对象获取到, 对比密码是否正确
        if (!password.equals(user.getPassword())) {
            //6. 如果密码不对抛异常, 密码错误
            throw new IncorrectCredentialsException("密码不对!");
        }


        //7. 如果密码正确, 封装返回的用户对象给shiro框架的Securitymanager核心
        //第一参数:用户对象, 第二参数:密码, 第三参数: 当前自定义realm对象的名称
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, this.getName());
        return info;
    }

}
